home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / WASTE 1.1 / WEInlineInput.c < prev    next >
Encoding:
Text File  |  1994-11-01  |  13.2 KB  |  580 lines  |  [TEXT/MPCC]

  1. // { WASTE PROJECT: }
  2. // { Inline Input Support }
  3.  
  4. // { Copyright © 1993-1994 Marco Piovanelli }
  5. // { All Rights Reserved }
  6. // C conversion by Dan Crevier
  7.  
  8. #include "WASTEIntf.h"
  9. #include "LongCoords.h"
  10.  
  11. #define myTypeQDPoint 'QDpt'
  12.  
  13. pascal OSErr _WEHiliteRangeArray(TextRangeArrayHandle hTray, WEHandle hWE)
  14. {
  15.     WEPtr pWE;
  16.     TextRangePtr pRange;
  17.     long rangeStart, rangeEnd;
  18.     short hiliteStyle;
  19.     WETextStyle ts;
  20.     short rangeIndex;
  21.     Boolean saveTrayLock;
  22.     OSErr err;
  23.  
  24.     pWE = *hWE;
  25.  
  26.     //{ lock down the range array }
  27.     saveTrayLock = _WESetHandleLock((Handle)hTray, true);
  28.     rangeIndex = (**hTray).fNumOfRanges - 1;
  29.     pRange = (*hTray)->fRange;
  30.  
  31.     //{ walk the hilite range array }
  32.     while (rangeIndex >= 0)
  33.     {
  34.  
  35.         //{ the offsets in the range array are relative to the beginning }
  36.         //{ of the active input area: convert them to absolute offsets }
  37.         rangeStart = pWE->tsmAreaStart + pRange->fStart;
  38.         rangeEnd = pWE->tsmAreaStart + pRange->fEnd;
  39.         hiliteStyle = pRange->fHiliteStyle;
  40.  
  41.         //{ take the absolute value of hiliteStyle }
  42.         hiliteStyle = ABS(hiliteStyle);
  43.  
  44.         //{ if hiliteStyle is kCaretPosition, set the selection range }
  45.         if (hiliteStyle == kCaretPosition)
  46.         {
  47.             pWE->selStart = rangeStart;
  48.             pWE->selEnd = rangeEnd;
  49.         }
  50.         else
  51.         {
  52.             hiliteStyle = hiliteStyle - kRawText;
  53.         }
  54.         //{ otherwise set the WETextStyle flags of the specified range appropriately }
  55.         if ((hiliteStyle >= 0) && (hiliteStyle <= 3))
  56.         {
  57.             ts.tsFlags = 0x10 + BSL(hiliteStyle, tsTSMSelected);
  58.             err = _WESetStyleRange(rangeStart, rangeEnd, weDoFlags, &ts, hWE);
  59.             if (err != noErr)
  60.             {
  61.                 goto cleanup;
  62.             }
  63.         }
  64.         
  65.         //{ go to next text range element }
  66.         rangeIndex = rangeIndex - 1;
  67.         pRange++;
  68.     }
  69.  
  70.     // { clear result code }
  71.     err = noErr;
  72.  
  73. cleanup:
  74.     //{ unlock the range array }
  75.     _WESetHandleLock((Handle)hTray, saveTrayLock);
  76.  
  77.     return err;
  78. }
  79.  
  80. pascal OSErr _WEHandleUpdateActiveInputArea(AppleEvent *ae, AppleEvent *reply,
  81.         long handlerRefCon)
  82. {
  83.     WEHandle hWE;
  84.     WEPtr pWE;
  85.     AEDesc text;
  86.     AEDesc hiliteTray;
  87.     TextRange pinRange;
  88.     long totalLength;
  89.     long fixLength;
  90.     long tsmOffset;
  91.     DescType returnedType;
  92.     long actualSize;
  93.     GrafPtr savePort;
  94.     WEActionHandle hAction;
  95.     Boolean saveAutoScroll;
  96.     Boolean saveTextLock;
  97.     Boolean saveWELock;
  98.     OSErr err;
  99.  
  100.     hWE = nil;
  101.  
  102.     //{ initialize descriptors to null values }
  103.     text.descriptorType = typeNull;
  104.     text.dataHandle = nil;
  105.     hiliteTray.descriptorType = typeNull;
  106.     hiliteTray.dataHandle = nil;
  107.  
  108.     //{ extract WE handle }
  109.     err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger, &returnedType,
  110.         (Ptr)&hWE, sizeof(hWE), &actualSize);
  111.     if (err != noErr)
  112.     {
  113.         goto cleanup;
  114.     }
  115.  
  116.     //{ lock the WE handle }
  117.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  118.     pWE = *hWE;
  119.  
  120.     //{ call the pre-update callback, if present }
  121.     if ((WETSMPreUpdateProcPtr)pWE->tsmPreUpdate != nil)
  122.     {
  123.         ((WETSMPreUpdateProcPtr)pWE->tsmPreUpdate)(hWE);
  124.     }
  125.  
  126.     //{ hide the caret if it's showing }
  127.     if (BTST(pWE->flags, weFCaretVisible))
  128.     {
  129.         _WEBlinkCaret(hWE);
  130.     }
  131.     
  132.     //{ extract the text descriptor }
  133.     err = AEGetParamDesc(ae, keyAETheData, typeChar, &text);
  134.     if (err != noErr)
  135.     {
  136.         goto cleanup;
  137.     }
  138.     
  139.     //{ get total length of text in the active input area }
  140.     totalLength = GetHandleSize(text.dataHandle);
  141.  
  142.     //{ extract the length of confirmed text in the active input area }
  143.     err = AEGetParamPtr(ae, keyAEFixLength, typeLongInteger, &returnedType,
  144.         &fixLength, sizeof(fixLength), &actualSize);
  145.     if (err != noErr)
  146.     {
  147.         goto cleanup;
  148.     }
  149.     //{ if fixLength = -1, all text is confirmed }
  150.     if (fixLength == -1)
  151.     {
  152.         fixLength = totalLength;
  153.     }
  154.     //{ if there's currently no active input area, open one }
  155.     if (pWE->tsmAreaStart == kInvalidOffset)
  156.     {
  157.         pWE->tsmAreaStart = pWE->selStart;
  158.         pWE->tsmAreaEnd = pWE->selEnd;
  159.         //{ if undo support is enabled, the inline session just started may initiate }
  160.         //{ a new typing sequence: if so, create a new action to track it }
  161.         if (BTST(pWE->flags, weFUndoSupport))
  162.         {
  163.             if (_WEIsTyping(hWE) == false)
  164.             {
  165.                 WEClearUndo(hWE);
  166.                 if (WENewAction(pWE->selStart, pWE->selEnd, 0, weAKTyping, 0, hWE, &hAction) == noErr)
  167.                 {
  168.                     if (WEPushAction(hAction) != noErr)
  169.                     {
  170.                         ;
  171.                     }
  172.                 }
  173.             }
  174.         }
  175.     }
  176.  
  177.     tsmOffset = pWE->tsmAreaStart;
  178.  
  179.     //{ the new text replaces whatever is in the active input area }
  180.     err = _WEDeleteRange(tsmOffset, pWE->tsmAreaEnd, hWE);
  181.     if (err != noErr)
  182.     {
  183.         goto cleanup;
  184.     }
  185.  
  186.     //{ synchronize the null style, so font script matches the keyboard script }
  187.     _WESynchNullStyle(hWE);
  188.  
  189.     //{ set the port font for good measure }
  190.     GetPort(&savePort);
  191.     SetPort(pWE->port);
  192.     TextFont(pWE->nullStyle.runStyle.tsFont);
  193.     SetPort(savePort);
  194.  
  195.     //{ temporarily lock the text }
  196.     saveTextLock = _WESetHandleLock(text.dataHandle, true);
  197.  
  198.     // { insert the text }
  199.     err = _WEInsertText(tsmOffset, *(text.dataHandle), totalLength, hWE);
  200.     if (err != noErr)
  201.     {
  202.         goto cleanup;
  203.     }
  204.     //{ unlock the text }
  205.     _WESetHandleLock(text.dataHandle, saveTextLock);
  206.  
  207.     //{ extract pin range }
  208.     err = AEGetParamPtr(ae, keyAEPinRange, typeTextRange, &returnedType, &pinRange,
  209.         sizeof(pinRange), &actualSize);
  210.     if (err == noErr)
  211.     {
  212.         //{ we want absolute offsets }
  213.         pinRange.fStart = pinRange.fStart + tsmOffset;
  214.         pinRange.fEnd = pinRange.fEnd + tsmOffset;
  215.     }
  216.     else
  217.     {
  218.         //{ a missing pin range descriptor isn't an error; everything else is }
  219.         if (err != errAEDescNotFound)
  220.         {
  221.             goto cleanup;
  222.         }
  223.         //{ default pin range is active input area }
  224.         pinRange.fStart = tsmOffset;
  225.         pinRange.fEnd = pWE->tsmAreaEnd;
  226.     }
  227.  
  228.     //{ extract the highlight range array }
  229.     err = AEGetParamDesc(ae, keyAEHiliteRange, typeTextRangeArray, &hiliteTray);
  230.     if (err != noErr)
  231.     {
  232.         if (err != errAEDescNotFound)
  233.         {
  234.             goto cleanup;
  235.         }
  236.     }
  237.     if (hiliteTray.dataHandle != nil)
  238.     {
  239.         err = _WEHiliteRangeArray((TextRangeArrayHandle)hiliteTray.dataHandle, hWE);
  240.         if (err != noErr)
  241.         {
  242.             goto cleanup;
  243.         }
  244.     }
  245.     else
  246.     {
  247.         pWE->selStart = tsmOffset + fixLength;
  248.         pWE->selEnd = pWE->selStart;
  249.     }
  250.  
  251.     //{ temporarily disable auto-scroll, as we need to scroll manually according to pinRange }
  252.     saveAutoScroll = BTST(pWE->flags, weFAutoScroll);
  253.     BCLR(pWE->flags, weFAutoScroll);
  254.     
  255.     //{ redraw the active input area }
  256.     err = _WERedraw(tsmOffset, tsmOffset + totalLength, hWE);
  257.     if (err != noErr)
  258.     {
  259.         goto cleanup;
  260.     }
  261.  
  262.     if (saveAutoScroll)
  263.     {
  264.     
  265.         //{ re-enable auto-scroll }
  266.         BSET(pWE->flags, weFAutoScroll);
  267.  
  268.         //{ scroll the pin range into view }
  269.         if (_WEScrollIntoView(pinRange.fStart, hWE) == false)
  270.         {
  271.             if (pinRange.fStart != pinRange.fEnd)
  272.             {
  273.                 _WEScrollIntoView(pinRange.fEnd, hWE);
  274.             }
  275.         }
  276.     }
  277.  
  278.     //{ update the boundaries of the active input area }
  279.     //{ if fixLength = totalLength, the inline input session is over: close the active input area }
  280.     if (fixLength == totalLength)
  281.     {
  282.         pWE->tsmAreaStart = kInvalidOffset;
  283.         pWE->tsmAreaEnd = kInvalidOffset;
  284.     }
  285.     else
  286.     {
  287.         //{ otherwise, fixLength defines the boundaries of the active input area }
  288.         pWE->tsmAreaStart = tsmOffset + fixLength;
  289.         pWE->tsmAreaEnd = tsmOffset + totalLength;
  290.  
  291.         //{ adjust undo buffer (if any) for the confirmed text }
  292.         _WEAdjustUndoRange(fixLength, hWE);
  293.     }
  294.  
  295.     //{ call the post-update callback, if present }
  296.     if (pWE->tsmPostUpdate != nil)
  297.     {
  298.         ((WETSMPostUpdateProcPtr)pWE->tsmPostUpdate)(hWE, fixLength, pWE->tsmAreaStart, pWE->tsmAreaEnd,
  299.             pinRange.fStart, pinRange.fEnd);
  300.     }
  301.     //{ clear result code }
  302.     err = noErr;
  303.  
  304. cleanup:
  305.     //{ clean up }
  306.     AEDisposeDesc(&text);
  307.     AEDisposeDesc(&hiliteTray);
  308.  
  309.     //{ unlock the WE record }
  310.     if (hWE !=NULL)
  311.     {
  312.         _WESetHandleLock((Handle)hWE, saveWELock);
  313.     }
  314.  
  315.     //{ return result code }
  316.     return err;
  317. }
  318.  
  319.  
  320. pascal OSErr _WEHandlePositionToOffset (AppleEvent *ae, AppleEvent *reply,
  321.         long handlerRefCon)
  322. {
  323.     WEHandle hWE;
  324.     WEPtr pWE;
  325.     Point position;
  326.     LongPt thePoint;
  327.     short regionClass;
  328.     long offset;
  329.     DescType returnedType;
  330.     long actualSize;
  331.     GrafPtr savePort;
  332.     char edge;
  333.     Boolean saveWELock;
  334.     OSErr err;
  335.  
  336.     hWE = nil;
  337.  
  338.     //{ extract WE handle }
  339.     err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger, &returnedType,
  340.         &hWE, sizeof(hWE), &actualSize);
  341.     if (err != noErr)
  342.     {
  343.         goto cleanup;
  344.     }
  345.  
  346.     //{ lock the WE record }
  347.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  348.     pWE = *hWE;
  349.  
  350.     // { extract position parameter }
  351.     err = AEGetParamPtr(ae, keyAECurrentPoint, myTypeQDPoint, &returnedType, &position,
  352.         sizeof(position), &actualSize);
  353.     if (err != noErr)
  354.     {
  355.             goto cleanup;
  356.     }
  357.     //{ convert position to local... }
  358.     GetPort(&savePort);
  359.     SetPort(pWE->port);
  360.     GlobalToLocal(&position);
  361.     SetPort(savePort);
  362.  
  363.     //{ ...and long coordinates }
  364.     WEPointToLongPoint(position, &thePoint);
  365.  
  366.     //{ find the byte offset and the edge value corresponding to the given position }
  367.     offset = WEGetOffset(&thePoint, &edge, hWE);
  368.  
  369.     // { add offset parameter to reply }
  370.     err = AEPutParamPtr(reply, keyAEOffset, typeLongInteger, &offset, sizeof(offset));
  371.     if (err != noErr) 
  372.     {
  373.         goto cleanup;
  374.     }
  375.     
  376.     //{ add edge parameter to reply }
  377.     err = AEPutParamPtr(reply, keyAELeftSide, typeBoolean, &edge, sizeof(edge));
  378.     if (err != noErr)
  379.     {
  380.         goto cleanup;
  381.     }
  382.     //{ determine the region class }
  383.     if (WELongPointInLongRect(&thePoint, &pWE->viewRect))
  384.     {
  385.         if (_WEOffsetInRange(offset, edge, pWE->tsmAreaStart, pWE->tsmAreaEnd))
  386.         {
  387.             regionClass = kTSMInsideOfActiveInputArea;
  388.         }
  389.         else
  390.         {
  391.                 regionClass = kTSMInsideOfBody;
  392.         }
  393.     }
  394.     else
  395.     {
  396.         regionClass = kTSMOutsideOfBody;
  397.     }
  398.     
  399.     //{ add region class parameter to reply }
  400.     err = AEPutParamPtr(reply, keyAERegionClass, typeShortInteger, ®ionClass,
  401.         sizeof(regionClass));
  402.     if (err != noErr)
  403.     {
  404.         goto cleanup;
  405.     }
  406.     
  407.     //{ clear result code }
  408.     err = noErr;
  409.  
  410. cleanup:
  411.     //{ unlock the WE record }
  412.     if (hWE != nil)
  413.     {
  414.         _WESetHandleLock((Handle)hWE, saveWELock);
  415.     }
  416.     
  417.     //{ return result code }
  418.     return err;
  419. }
  420.  
  421. pascal OSErr _WEHandleOffsetToPosition(AppleEvent *ae, AppleEvent *reply, long handlerRefCon)
  422. {
  423.     WEHandle hWE;
  424.     WEPtr pWE;
  425.     long offset;
  426.     LongPt thePoint;
  427.     Point position;
  428.     short lineHeight;
  429.     DescType returnedType;
  430.     long actualSize;
  431.     GrafPtr savePort;
  432.     Boolean saveWELock;
  433.     OSErr err;
  434.  
  435.     hWE = nil;
  436.  
  437.     //{ extract WE handle }
  438.     err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger, &returnedType, &hWE,
  439.         sizeof(hWE), &actualSize);
  440.     if (err != noErr)
  441.     {
  442.         goto cleanup;
  443.     }
  444.  
  445.     //{ lock the WE record }
  446.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  447.     pWE = *hWE;
  448.  
  449.     //{ if there's no active input area, return errOffsetInvalid }
  450.     if (pWE->tsmAreaStart < 0)
  451.     {
  452.         err = errOffsetInvalid;
  453.         goto cleanup;
  454.     }
  455.     
  456.     //{ extract the offset parameter }
  457.     err = AEGetParamPtr(ae, keyAEOffset, typeLongInteger, &returnedType, &offset, 
  458.         sizeof(offset), &actualSize);
  459.     if (err != noErr)
  460.     {
  461.         goto cleanup;
  462.     }
  463.  
  464.     //{ offset is relative to the beginning of the active input area; we want an absolute offset }
  465.     offset = offset + pWE->tsmAreaStart;
  466.  
  467.     // { make sure the offset is within the input area }
  468.     if ((offset < pWE->tsmAreaStart) || (offset >= pWE->tsmAreaEnd))
  469.     {
  470.         err = errOffsetInvalid;
  471.         goto cleanup;
  472.     }
  473.  
  474.     //{ find the position corresponding to the given offset (in long coordinates) }
  475.     WEGetPoint(offset, &thePoint, &lineHeight, hWE);
  476.     thePoint.v = thePoint.v + lineHeight;
  477.  
  478.     //{ make sure offset is within view rectangle }
  479.     if (!WELongPointInLongRect(&thePoint, &pWE->viewRect))
  480.     {
  481.         err = errOffsetIsOutsideOfView;
  482.         goto cleanup;
  483.     }
  484.  
  485.     //{ convert the point to short... }
  486.     WELongPointToPoint(&thePoint, &position);
  487.  
  488.     //{ ...and global coordinates }
  489.     GetPort(&savePort);
  490.     SetPort(pWE->port);
  491.     LocalToGlobal(&position);
  492.     SetPort(savePort);
  493.  
  494.     //{ add keyAEPoint parameter to the reply Apple event }
  495.     err = AEPutParamPtr(reply, keyAEPoint, myTypeQDPoint, &position, sizeof(position));
  496.     if (err != noErr)
  497.     {
  498.         goto cleanup;
  499.     }
  500.  
  501.     //{ add keyAETextFont parameter to the reply Apple event }
  502.     err = AEPutParamPtr(reply, keyAETextFont, typeShortInteger, &pWE->nullStyle.runStyle.tsFont,
  503.         sizeof(pWE->nullStyle.runStyle.tsFont));
  504.     if (err != noErr)
  505.     {
  506.         goto cleanup;
  507.     }
  508.     
  509.     //{ add keyAETextPointSize parameter to the reply Apple event }
  510.     err = AEPutParamPtr(reply, keyAETextPointSize, typeShortInteger, 
  511.         &pWE->nullStyle.runStyle.tsSize, sizeof(pWE->nullStyle.runStyle.tsSize));
  512.     if (err != noErr)
  513.     {
  514.         goto cleanup;
  515.     }
  516.  
  517.     //{ add keyAETextLineAscent parameter to the reply Apple event }
  518.     err = AEPutParamPtr(reply, keyAETextLineAscent, typeShortInteger, 
  519.         &pWE->nullStyle.runAscent, sizeof(pWE->nullStyle.runAscent));
  520.     if (err != noErr)
  521.     {
  522.         goto cleanup;
  523.     }
  524.     
  525.     //{ add keyAETextLineHeight parameter to the reply Apple event }
  526.     err = AEPutParamPtr(reply, keyAETextLineHeight, typeShortInteger, 
  527.         &pWE->nullStyle.runHeight, sizeof(pWE->nullStyle.runHeight));
  528.     if (err != noErr)
  529.     {
  530.         goto cleanup;
  531.     }
  532.     
  533.     //{ clear result code }
  534.     err = noErr;
  535.  
  536. cleanup:
  537.     //{ unlock the WE record }
  538.     if (hWE != nil)
  539.     {
  540.         _WESetHandleLock((Handle) hWE, saveWELock);
  541.     }
  542.     
  543.     //{ return result code }
  544.     return err;
  545. }
  546.  
  547. pascal OSErr WEInstallTSMHandlers(void)
  548. {
  549.     OSErr err;
  550.     
  551.     //{ install Apple Event handlers to be used by Text Service components }
  552.     err = AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea,
  553.         NewAEEventHandlerProc(_WEHandleUpdateActiveInputArea), 0, false);
  554.     if (err != noErr)
  555.     {
  556.         goto cleanup;
  557.     }
  558.         
  559.     err = AEInstallEventHandler(kTextServiceClass, kPos2Offset, 
  560.         NewAEEventHandlerProc(_WEHandlePositionToOffset), 0, false);
  561.     if (err != noErr)
  562.     {
  563.         goto cleanup;
  564.     }
  565.     
  566.     err = AEInstallEventHandler(kTextServiceClass, kOffset2Pos, 
  567.         NewAEEventHandlerProc(_WEHandleOffsetToPosition), 0, false);
  568.     if (err != noErr)
  569.     {
  570.         goto cleanup;
  571.     }
  572.     
  573.     // { clear result code }
  574.     err = noErr;
  575.  
  576. cleanup:
  577.     // { return result code }
  578.     return err;
  579. }
  580.